#include <common.h>
#include <stdlib.h>
#include <stdio.h>
#include <string.h>
#include <tproto.h>
#include <crc16.h>
#include <protocmd.h>
#include <dataapi.h>

TBuffer *createRomBuffer(char *Address, int size)
{
	TBuffer *ret=(TBuffer*)udk_malloc(sizeof(TBuffer));
	ret->buffer=(unsigned char *)Address;
	ret->bufferSize=size;
	ret->bufEnd=ret->buffer+size;
	ret->bufPtr=ret->buffer;
	ret->isRom=1;
	return ret;
}

TBuffer *createRamBuffer(int size)
{
	TBuffer *ret=createRomBuffer((char*)udk_malloc(size), size);
	ret->isRom=0;
	return ret;
}

void freeBuffer(TBuffer *buffer)
{
	if(buffer==NULL) return;
	if((buffer->buffer) && (!buffer->isRom))
		udk_free(buffer->buffer);
	udk_free(buffer);
}

int writeBuffer(TBuffer *buffer, char *data, int size)
{
	if(size>resOfBuffer(buffer)) size=resOfBuffer(buffer);
	memcpy(buffer->bufPtr, data, size);
	buffer->bufPtr+=size;
	return size;
}

int writeBufferAuto(TBuffer *buffer, char *data, int size)
{
	int len=size-resOfBuffer(buffer);
	if(len>0)
	{
		if(len<10*1024) len=10*1024;
		len+=buffer->bufferSize;
		if(resizeRamBuffer(buffer, len)!=len) return 0;
	}
    memcpy(buffer->bufPtr, data, size);
	buffer->bufPtr+=size;
	return size;
}

int insertBufferAuto(TBuffer *buffer, char *data, int size, int offset)
{
	unsigned char *p;
	int i,len=size-resOfBuffer(buffer);
	if(len>0)
	{
		if(len<10*1024) len=10*1024;
		len+=buffer->bufferSize;
		if(resizeRamBuffer(buffer, len)!=len) return 0;
	}
	p=buffer->bufPtr+size-1;
	for(i=buffer->bufPtr-buffer->buffer-offset;i>0;i--){ *p=*(p-size); p--;}
    memcpy(buffer->buffer+offset, data, size);
	buffer->bufPtr+=size;
	return size;
}

int resizeRamBuffer(TBuffer *buffer, int newSize)
{
	int i=buffer->bufPtr-buffer->buffer;
	unsigned char *p;
	if(buffer->isRom) return 0;
	p=(unsigned char *)realloc(buffer->buffer, newSize);
	if(p==NULL) return 0;
	buffer->buffer=p;
	buffer->bufferSize=newSize;
	buffer->bufEnd=buffer->buffer+newSize;
	buffer->bufPtr=buffer->buffer+i;
	return newSize;
}

int resOfBuffer(TBuffer *buffer)
{
	return buffer->bufEnd-buffer->bufPtr;
}


/*
初始化ProtoBuf结构,分配必要的内存，返回内存长度
*/
int initProtoBuf(TProtoBuf *protoBuf)
{
	protoBuf->bufferSize = 1024;
	protoBuf->buffer = (unsigned char*)malloc(protoBuf->bufferSize);
	protoBuf->bufPtr = protoBuf->buffer;
	protoBuf->protoHead.startTag = 0xaa;
	protoBuf->protoHead.endTag =0x55;
	protoBuf->data = protoBuf->buffer + 4;
	return 1024;
}

/*
释放ProtoBuf占用的内存
*/
int freeProtoBuf(TProtoBuf *protoBuf)
{
	if(protoBuf->buffer)
		free(protoBuf->buffer);
	return 0;
}

/*
	开始标记	目标地址	命令字	数据总长度	参数及数据	CRC16校验	结束标记
内容	0xaa															0x55
长度	1byte	1byte		1 byte	2byte		N byte		2byte		1byte
*/
int serialProtoBuf(TProtoBuf *protoBuf)
{
	unsigned char *p=protoBuf->buffer;
	//
	*(p) = protoBuf->protoHead.startTag;
	*(p+1) = protoBuf->protoHead.destAddr;

	*(p+2) = protoBuf->command;
	*(unsigned short*)(p+3) = protoBuf->dataSize;
	if(protoBuf->dataSize>0)
		memcpy(p+5,protoBuf->data,protoBuf->dataSize);

	*(unsigned short*)(p+5+protoBuf->dataSize) = crc16(p+1,4+protoBuf->dataSize);

	*(p+5+protoBuf->dataSize+2) = protoBuf->protoHead.endTag;
	protoBuf->size = 8+protoBuf->dataSize;
	return protoBuf->size;
}

/*
检查传入数据的有效性
*/

int deserialProtoBuf(TProtoBuf *protoBuf,const char *buffer)
{
	unsigned char *p = protoBuf->buffer;
	protoBuf->command = *(p+2);
	protoBuf->dataSize = *(unsigned short*)(p+3);
	protoBuf->data = protoBuf->buffer + 4;
	return protoBuf->dataSize;
}

/*
传入URL请求，转换为ZKProtoBuf格式
*/

int data2ProtoBuf(const char *query, TProtoBuf *protoBuf)
{
	int ret, qlen=query?strlen(query):0;
	char *action, *table, *fields, *filter, *options;
	if(qlen<=0) return ERROR_QUERY;
	//table[0]=0; filter[0]=0; fields[0]=0; options[0]=0;

	//printf("URL: %s  %s\n", query, data);
	//提取各种类型数据
	if(!(action=get_var("Action", query, qlen)))
		return ERROR_PARAM;
	
	table = get_var("Table", query, qlen);
	fields = get_var("Fields", query, qlen);
	filter = get_var("Filter", query, qlen);
	options = get_var("Options", query, qlen);

	if(strcasecmp(action, "infoQuery")==0)
	{
		protoBuf->size = 8;
		protoBuf->command = CMD_GET_DEVICE_PARAM;
		protoBuf->dataSize = 1;
		*(protoBuf->data) = 1;
		return serialProtoBuf(protoBuf);
	}
	return 0;
}

/*
*/

int protoBuf2Data(const char *buffer,TProtoBuf *protoBuf)
{
	int ret;
	if(deserialProtoBuf(protoBuf,buffer)==0)
		return 0;

	if(protoBuf->command == CMD_GET_DEVICE_PARAM)	//infoQuery
	{
		if(protoBuf->dataSize>0)
			memcpy((char *)buffer,protoBuf->data,protoBuf->dataSize);
		return protoBuf->dataSize;
	}
	return 0;
}

